 package com.qq.XML.dom4j;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.List;
/*
	@XML解析：
	使用程序读取XML中的数据，很多时候是框架底层技术，我们用的不多
	并不需要我们自己写IO流代码去读取xml文件中的数据。
	其实有很多开源的，好用的XML解析框架，最知名的是DOM4J
	
	两种解析方式：
	SAX解析：每读一行到内存解析一行——————适合大文件
	DOM解析：是把整个XML文件读到内存中——————不适合大文件
	一般还是用DOM的dom4j技术框架 因为一般文件也没那么大
	
	Dom常见的解析工具：
	JAXP	SUN公司提供的一套XML的解析的API
	
	JDOM	JDOM是一个开源项目，它基于树型结构，
			利用纯JAVA的技术对XML文档实现解析、生成、序列化以及多种操作。
			
	dom4j	是JDOM的升级品，用来读写XML文件的。
			具有性能优异、功能强大和极其易使用的特点，
			它的性能超过sun公司官方的dom 技术，
			同时它也是一个开放源代码的软件，
			Hibernate也用它来读写配置文件。
			
	jsoup	功能强大DOM方式的XML解析开发包，尤其对HTML解析更加方便
	
	
	学会使用dom4j解析XML文件中的数据：
	1.下载Dom4j框架，官网下载。
	2.在项目中创建一个文件夹：lib
	3.将dom4j-2.1.1.jar文件复制到 lib 文件夹
	4.在jar文件上点右键，把jar包导入到项目依赖库
	5.在类中导包使用
	
	commons-io-2.11.0.jar				核心jar包 ———都是源码编译后的class文件		
	commons-io-2.11.0-javadoc.jar		API文档包———教你怎么用
	commons-io-2.11.0-sources.jar		源代码包———怎么做出来的
	
	DOM解析解析文档对象模型：
	SAXReader对象——解析器对象
	Document对象——整个xml文档
	Element对象——元素（标签）节点 
	Attribute对象——属性节点 
	Text对象——数据节点（文本节点）
	注：都是Node节点类型，继承共同Node接口
	
	Dom4j解析XML的元素、属性、文本：
	SAXReader类构造器:
	public SAXReader() 			创建Dom4J的解析器对象代表整个dom4j框架
	SAXReader类方法:
	Document read(String url)	加载XML文件成为Document对象（通过文件路径或字节流）
	
	Document类方法:
	Element getRootElement() 	获得根元素对象
	
	Element类方法:
	List<Element> elements()			得到当前元素下所有(一级)子元素
	List<Element> elements(String name)	得到当前元素下指定名字的子元素返回集合
	Element element(String name)		得到当前元素下指定名字的子元素,如果有很多名字相同的返回第一个
	
	String getName()					得到当前元素名字
	Attribute attribute (String name)   通过属性名得到当前元素的属性对象
	String getText()					得到当前元素的文本 getTextTrim()去空格
	String attributeValue(String name)	通过属性名直接得到当前元素的属性值	
	String elementText(String name)		得到指定名称的子元素的文本 elementTextTrim()去空格
	List<Attribute> attributes()		得到当前元素的属性对象集合
	
	
	注：
	其实就是从上往下依次获取对象，调用方法得到子元素对象以及各种属性等等
 	*/


 
public class Dom4JTest {
    @Test
    public void parseXMLData() throws Exception {
        // 1、创建一个Dom4j的解析器对象（底层创建了字符流），代表了整个dom4j框架
        SAXReader saxReader = new SAXReader();

        // 2、把XML文件加载到内存中成为一个Document文档对象
        // idea中虽然是相对路径但也需要通过模块名去定位，如果修改模块名可能造成定位不了文件，
        // Document document = saxReader.read(new File("xml-app\\src\\Contacts.xml")); 
        // Document document = saxReader.read(new FileInputStream("xml-app\\src\\Contacts.xml"));
        
        // 所以为了直接从src（项目关联的文件放src-类路径）下寻找文件，要获取类的字节输入流来定位文件
        // getResourceAsStream中的/是直接去src下寻找的文件
        // InputStream is = Dom4JTest.class.getResourceAsStream("/Contacts.xml");
        // Document document = saxReader.read(is);
        
        // eclipse中相对路径就是直接在src下定位文件，没有模块所以不担心修改模块名的问题 
        Document document = saxReader.read(new File("src\\Contacts.xml")); 
        // 3、获取根元素对象
        Element root = document.getRootElement();
        System.out.println(root.getName());

        // 4、拿根元素下的全部子元素对象(一级)
        // List<Element> sonEles =  root.elements();
        List<Element> sonEles =  root.elements("contact");
        for (Element sonEle : sonEles) {
            System.out.println(sonEle.getName());
        }

        // 拿某个子元素
        Element userEle = root.element("user");
        // 获取元素名
        System.out.println(userEle.getName());
        // 默认提取第一个子元素对象 
        Element contact = root.element("contact");
        System.out.println(contact.getText());//换行符也算文本
        // 获取子元素文本
        System.out.println(contact.elementText("name"));
        // 获取子元素文本并去掉前后空格
        System.out.println(contact.elementTextTrim("name"));
        // 获取当前元素下的子元素对象
        Element email = contact.element("email");
        // 获取当前元素文本
        System.out.println(email.getText());
        // 获取当前元素文本并去掉前后空格
        System.out.println(email.getTextTrim());
        // 根据属性名获取属性对象
        Attribute idAttr = contact.attribute("id");//属性可以有多个
        System.out.println(idAttr.getName() + "-->" + idAttr.getValue());
        // 根据属性名直接提取属性值
        System.out.println(contact.attributeValue("id"));
        System.out.println(contact.attributeValue("vip"));




    }
}
